package com.devmindset.legoframework.client.mvc;

import java.util.HashMap;
import com.allen_sauer.gwt.log.client.Log;
import com.devmindset.legoframework.client.mvc.binding.Model;

/**
 * Model to be used as the base model from which {@link LegoComponent} objects can 
 * construct and recalculate themselves.
 * 
 * To be used as part of {@link LegoEvent}.
 * 
 * @author <a href="mailto:ice.penov@devmindset.com">Ice Penov</a>
 */
public final class LegoModel {
  
  private Object modelData;
  private HashMap<String, Object> additionalProperties = new HashMap<String, Object>();  
  
  /**
   * Constructor.
   * 
   * @param modelData the main modelData of this {@link LegoModel} 
   */
  public LegoModel(Object modelData) {
    this.modelData = modelData;
  }
  
  /**
   * Constructor.
   * 
   * @param modelData the main modelData of this {@link LegoModel} 
   * @param additionalProperties the additional properties supplied to this {@link LegoModel}
   */
  public LegoModel(Object modelData, HashMap<String, Object> additionalProperties) {
    this(modelData);
    this.additionalProperties = additionalProperties;
  }

  /**
   * Returns the model data.
   * 
   * @param <X> data target return type
   * 
   * @return the modelData
   */
  @SuppressWarnings("unchecked")
  public <X> X getModelData() {
    return (X) modelData;
  }

  /**
   * Returns the additionalProperties passed along with this {@link LegoModel}.
   *
   * @return the additionalProperties
   */
  public HashMap<String, Object> getProperties() {
    return additionalProperties;
  }
  
  /**
   * Adds an additional property to the base {@link Model} of this {@link LegoModel}.
   * Any object can be passed as a property. 
   * 
   * Use the {@link LegoModel#getProperties()} to retrieve the properties for this model.
   * 
   * @param key the property key identifier
   * @param property the property itself
   */
  public void addProperty(String key, Object property) {
    if (key != null && property != null) {
      if (!additionalProperties.containsKey(key)) {
        additionalProperties.put(key, property);
        Log.debug("Added property with key [ " + key + " ] to model [ " + this + " ]");
      } else {
        Log.warn("The supplied property key [ " + key + " ] is already present in the model. "
            + "Property will not be added.");        
      }
    } else {
      Log.warn("Either the property key or the property itself was null. Property will not be added.");
    }
  }
  
  /**
   * Gets the property designated by key for this model.
   * 
   * @param <X> the return type
   * @param key the property key
   * 
   * @return the property
   */
  @SuppressWarnings("unchecked")
  public <X> X getProperty(String key) {
    if (key != null) {
      return (X) additionalProperties.get(key);
    } else {
      Log.warn("Didn't find property from model with key [ " + key + " ]");
      return null;
    }
  }

}